<?php
set_include_path(get_include_path().PATH_SEPARATOR.'pear'.PATH_SEPARATOR.'../pear');
require_once 'DB.php';

if(!isset($nofonctions))
  {
    require_once 'php/fonctions.php';
  }

/**
 * Classe SQL contenant toutes les requêtes utiles à phpLister
 * @todo extends de pear::BD plutôt que d'encapsuler ?
 */
class SQL
{
  
  private static $instance ; 
  private $sql;
  private $debug;
  private $prefix;
  
  /**
   * Retourne une instance de la class, utilisation comme un singleton
   */
  public static function GetInstance() 
  { 
    if(!isset(self::$instance)) 
      { 
	self::$instance = new SQL();
      } 
    return self::$instance; 
  }
  
  /**
   * Contructeur de SQL, démarre une connexion à la base
   */
  private function __construct()
  {
    global $CONF;
    $dsn = 
      $CONF['sql_type'].'://'.
      $CONF['sql_user'].':'.
      $CONF['sql_pass'].'@'.
      $CONF['sql_host'].'/'.
      $CONF['sql_db'];    
    
    $this->prefix = $CONF['sql_prefix'];
    $this->sql    = DB::connect($dsn);
    
    if(DB::isError($this->sql)) 
      {    
	throw(new ListerException($this->sql->getMessage()));
      }
    
    $this->sql->createSequence($this->prefix.'item');
    $this->sql->setFetchMode(DB_FETCHMODE_ASSOC);
    $this->debug = false;
  }
  
  public function getPrefix(){
    return $this->prefix;
  }
  
  
  /* -------------------------------- */
  /* Méthodes de récupération en base */
  /* -------------------------------- */
  
  /**
   * Methode qui retourne les options de configurations
   *
   * @param string $option
   * @return array $CONF options de configuration
   */
  public function getConfiguration($option = null)
  {
    $condition = '';
    if(!is_null($option))
      {
	$condition = 'WHERE nomOption="'.$option.'"';
      }
    
    $requete = 'SELECT * FROM '.$this->prefix.'options '.$condition;
    if(!is_null($option))
      {
	return $this->doRequeteLigne($requete);
      }
    
    return $this->doRequeteLignes($requete);
  }
  
  /**
   * Méthode qui retourne tous les items qui sont en base
   *
   * @todo documenter les params
   * @param mixed $param Clauses de séléction
   * @return mixed $m Tableau contenant les infos de tous les items ou si $count est rensigne un string de la requete sans 'SELECT *'
   */
  public function getItems($tris='dateD', $tabTags=null, $tabTypes=null, $recherche=null, $page=1, $count=null)
  {
    /* Récupération des infos sur l'utilisateur en cours */
    /* ------------------------------------------------- */
    // Récupération du login
    $login = $_SESSION['LOGIN'];
    $admin = (int)$_SESSION['IS_ADMIN'];
    
    $listTags = $conditionTags = $jointureTags = $listTypes = $conditionRecherche = null;

    /* Séléction de la methode de tris */
    /* ------------------------------- */
    $methodeTris = null;
    switch($tris)
      {
      case 'dateA' : $methodeTris = 'i.dateAjoutItem ASC';  break;
      case 'nomA'  : $methodeTris = 'i.nomItem ASC';        break;
      case 'nomD'  : $methodeTris = 'i.nomItem DESC';       break;
      default      : $methodeTris = 'i.dateAjoutItem DESC'; break;
      }

    /* Sélection des tags */
    /* ------------------ */
    if(!is_null($tabTags))
      {
	// Fait la liste des tags sous la forme : 'tag1','tag2'
	$listTags      = "'" . implode("','", $tabTags) . "'";
	$conditionTags = 'ti.nomTag IN('.$listTags.')';
	$jointureTags  = 'LEFT JOIN '.$this->prefix.'tag_item ti ON i.idItem=ti.idItem';
	$having        = 'HAVING COUNT(DISTINCT nomTag) >= '.count($tabTags);
      }

    /* Sélection des types */
    /* ------------------- */
    if(!is_null($tabTypes))
      {	
	// Fait la liste des types sous la forme : 1,2,4
	$listTypes      = implode(',',$tabTypes);
	$conditionTypes = 'typeItem IN('.$listTypes.')';
      }

    /* Construction de la condition de recherche */
    /* ----------------------------------------- */
    if(!is_null($recherche))
    {
        $recherche  = $this->cleanSQL($recherche);
        $rechercheT = explode(' ', $recherche);

        $conditionRecherche = ' ( 1 ';
        foreach($rechercheT as $recherche) 
        {
            if(ereg(':', $recherche)) // recherche dans les metas données (meta:valeur)
            {
                $r      = explode(':', $recherche);
                $meta   = array_shift($r);
                $chaine = implode(':', $r);
                if($meta == 'user') 
                {
                    $conditionRecherche .= ' AND i.proprietaireItem="'.$chaine.'" ';
                } 
                elseif($meta == '~')
                {
                    $conditionRecherche .= 
                        " AND (".$this->orthographeApproch($chaine,'i.nomItem').")";
                }
                else 
                {
                    $conditionRecherche .= ' AND i.metaItem LIKE(\'%<'.$meta.'>%'.$chaine.'%</'.$meta.'>%\')';
                }
            }
            else // recherche dans le nom
            {
                $conditionRecherche .= ' AND i.nomItem LIKE(\'%'.$recherche.'%\')';
            }
        }
        $conditionRecherche .= ') ';
    }

    
    /* Construction de la requete */
    /* -------------------------- */
    // Selection des attributs
    $debut   = '
SELECT i.idItem, i.nomItem, i.lienItem, i.descItem, i.iconeItem, i.dateAjoutItem, i.proprietaireItem, i.typeItem, i.metaItem, d.droits ';
    
    $requete = ' 
FROM '.$this->prefix.'item i LEFT JOIN '.$this->prefix.'droits d ON d.idItem = i.idItem ';
    
    // Ajout de la jointure pour les tags
    if(!is_null($listTags))
      $requete .= ' '.$jointureTags;

    // Ajout des conditions sur les droits
    global $visiteur;
    $requete .= ' WHERE 
(
i.proprietaireItem=\''.$login.'\'
OR ( d.login=\''.$login.'\' AND d.droits>=1 )
OR ( d.login=\''.$visiteur.'\' AND d.droits>=1)
OR '.$admin.'
)';
    
    // Ajout des conditions sur les tags
    if(!is_null($listTags))  $requete .= ' AND ' . $conditionTags;

    // Ajout des conditions sur les types
    if(!is_null($listTypes)) $requete .= ' AND ' . $conditionTypes;

    // Ajout de la condition de recherche
    if(!is_null($conditionRecherche)) $requete .= ' AND ' . $conditionRecherche;
    
    // Ajout du group by
    $requete .= ' GROUP BY i.idItem';

    // Ajout du having pour les tags
    if(!is_null($listTags)) $requete .= ' ' . $having;
    
    if(!is_null($count))
      {
	return $requete;
      }

    // Ajout de la condition de tris
    $requete .= ' ORDER BY '.$methodeTris.' ';
    $requete  = $debut.$requete;

    // Limit
    global $CONF;
    $nb    = $CONF['nbr_par_page'];
    $from  = 0 + (($page - 1) * $nb);

//echo '<pre>'.$requete;exit;

    return $this->doRequeteLignes($requete, $from, $nb);
  }
  
  /**
   * Methode qui retourne le nombre d'item repondant aux criteres
   *
   * @see SQL::getItems() pour les parametres
   * @param &int $nb nombre d'item
   * @return array $t tableau des id des items qui repondent aux criteres
   */
  public function getIdItems($tris='dateD', $tabTags=null, $tabTypes=null, $recherche=null, &$nb)
  {
    $requete = $this->getItems($tris, $tabTags, $tabTypes, $recherche, 1, 1);

    $requete = 'SELECT i.idItem '.$requete;
    $result  = $this->doRequeteLignes($requete);

    if(!is_array($result))
      {
	throw new ListerException($result->getMessage());
      }

    $nb = count($result);
    return $result;
  }

  /**
   * Méthode qui retourne tous les tags qui sont en base
   *
   * @todo param pour order by hit (nom par defaut)
   * @return array $t Tableau contenant les infos de tous les tags
   */
  public function getTags()
  {
    
    $requete = 'SELECT * FROM '.$this->prefix.'tag ORDER BY nomTag';
    return $this->doRequeteLignes($requete);
  }

  /**
   * Méthode qui retourne tous les tags d'un item
   *
   * @param int $id ID de l'item
   * @return array $res Tableau contenant le nom de tous les tags de l'item
   */
  public function getTagsItem($id)
  {
    // Essayer au maximum de passer dans getTagsItemAndUtilisateurDroitsItem
    $requete = 'SELECT nomTag FROM '.$this->prefix.'tag_item WHERE idItem=\''.(int)$id.'\'';
    $tmp     = $this->doRequeteLignes($requete);
    $res     = array();    

    foreach($tmp as $unTmp)
      {
	$res[] = $unTmp['nomTag'];
      }

    return $res;
  }

/**
* Méthode issu de la fusion de getTagsItem et getUtilisateurDroitsItem
*
*/
  public function getTagsItemAndUtilisateurDroitsItem($id)
  {
      $requete = 'SELECT nomTag, login, droits FROM '.$this->prefix.'droits d LEFT JOIN '.$this->prefix.'tag_item t ON t.idItem = d.idItem WHERE d.idItem='.(int)$id;
      
    $tmp     = $this->doRequeteLignes($requete);
    $res     = array();    

    foreach($tmp as $unTmp)
      {
    	if(!empty($unTmp['nomTag']) && !in_array($unTmp['nomTag'],$res))
	      $res[] = $unTmp['nomTag'];
      }
      
    return array($tmp,$res);
  }

  /**
   * Méthode qui retourne tous les tags d'une categorie rootTag
   *
   * @param int $id ID de la categorie rootTag
   * @return array $t Tableau contenant le nom de tous les tags de la categorie
   */
  public function getTagsCateg($id)
  {
    
    $requete = 'SELECT nomTag FROM '.$this->prefix.'tag WHERE idRootTag=\''.(int)$id.'\'';
    $tmp     = $this->doRequeteLignes($requete);
    $res     = array();    

    foreach($tmp as $unTmp)
      {
	$res[] = $unTmp->nomTag;
      }

    return $res;
  }

  /**
   * Méthode qui retourne les infos de l'item
   *
   * @param int $id Identifiant de l'item à récupérer
   * @return array $t Tableau contenant les infos de l'item
   */  
  public function getItem($id)
  {
    /* Récupération des infos sur l'utilisateur en cours */
    /* ------------------------------------------------- */
    // Récupération du login
    $login = $_SESSION['LOGIN'];
    $admin = (int)$_SESSION['IS_ADMIN'];
    global $visiteur;

    $requete = '
SELECT i.idItem, i.nomItem, i.descItem, i.lienItem, i.iconeItem, i.dateAjoutItem, i.proprietaireItem, i.typeItem, i.metaItem, d.droits 
FROM '.$this->prefix.'item i
LEFT JOIN '.$this->prefix.'droits d ON i.idItem = d.idItem
WHERE
i.idItem = '.(int)$id.' AND
  (
    '.$admin.' OR
    i.proprietaireItem = \''.$login.'\' OR
    (( d.login=\''.$login.'\' AND d.droits>=1 )) OR
    (  d.login=\''.$visiteur.'\')
  )
';
    //$requete = 'SELECT * FROM '.$this->prefix.'item WHERE idItem='.(int)$id;
    $res     = $this->doRequeteLigne($requete);
    $tags    = array();

    if(!empty($res))
      {
	$res['tags'] = $this->getTagsItem($id);
	return $res;
      }
    else
      {
	throw new ListerException(5, $id);
      }
  }
  
  /**
   * Méthode qui retourne les logins de tous les utilisateurs
   *
   * @return array $t Tableau contenant les login des utilisateurs
   */
  public function getUtilisateurs($page=1)
  {
    
    $requete = 'SELECT loginUtilisateur FROM '.$this->prefix.'utilisateur ORDER BY loginUtilisateur';
    
    if($page != 'all')
    {
        global $CONF;
        $nb    = $CONF['nbr_par_page_u'];
        $from  = 0 + (($page - 1) * $nb);

        return $this->doRequeteLignes($requete, $from, $nb);
    }
    else
    {
        return $this->doRequeteColonne($requete);
    }
  }
  
  public function getNbUtilisateur()
  {
    $requete = 'SELECT COUNT(*) AS nb FROM '.$this->prefix.'utilisateur';
    $nb = $this->doRequeteLigne($requete);
    return (int)$nb['nb'];
  }

  /**
   * Méthode qui retourne les infos de l'utilisateur
   *
   * @param string $login Login de l'utilisateur dont il faut récupérer les infos
   * @return array $t Tableau contenant les infos de l'utilisateur
   */
  public function getUtilisateur($login)
  {
    $tmp = null;
    if (is_numeric($login))
      {
	$requete = 'SELECT * FROM '.$this->prefix.'utilisateur u WHERE u.idUtilisateur=\''.$login.'\'';
	$tmp = $this->doRequeteLigne($requete);
      }

    if (empty($tmp))
      {
	$requete = 'SELECT * FROM '.$this->prefix.'utilisateur u WHERE u.loginUtilisateur=\''.$login.'\'';
	$tmp = $this->doRequeteLigne($requete);
      }

    //    var_dump($tmp); exit;

    if(!empty($tmp))
      {
	return $tmp;
      }
    else
      {
	throw(new ListerException(13, $login));
      }
  }
  
  /**
   * Méthode qui retourne les infos d'un tag
   *
   * @param string $nom Nom du tag à récupérer
   * @return array $t Tableau contenant les infos de l'item
   */  
  public function getTag($nom)
  {
    $requete = 'SELECT * FROM '.$this->prefix.'tag WHERE nomTag=\''.$nom.'\'';
    return $this->doRequeteLigne($requete);
  }

  /**
   * Méthode qui retourne des stats sur le nombre de hit total sur les tags
   *
   * @return array $t tableau des stats
   */
  public function getStatsHitTag()
  {
    $requete = 'SELECT MIN(hitTag) as minHitTag, MAX(hitTag) as maxHitTag, AVG(hitTag) AS avgHitTag, SUM(hitTag) AS sumHitTag FROM '.$this->prefix.'tag';
    return $this->doRequeteLigne($requete);
  }

  /**
   * Méthode qui retourne les utilisateurs qui ont le droit de lire ou ecrire sur l'item
   *
   * @param int $idItem id de l'item
   * @return array $u liste des logins des utilisateurs avec leur droit
   */
  public function getUtilisateurDroitsItem($idItem)
  {
      die('ERREUR MARQUEUR 0x02 :-D techniquement personne ne devrait voir ça se referer au code php sinon (SQL.php)'); // On ne doit plus jamais passer ici mais plutôt dans getTagsItemAndUtilisateurDroitsItem
    $requete = 'SELECT login, droits FROM '.$this->prefix.'droits WHERE idItem = '.(int)$idItem;
    return $this->doRequeteLignes($requete);
  }
  
  /* ------------------------ */
  /* Méthodes d'ajout en base */
  /* ------------------------ */
  
  /**
   * Méthode qui enregistre une nouvelle option
   *
   * @param string $nomOption nom de l'option
   * @param string $valOption valeur de l'option
   * @param string $typeOption type de l'option ("int"|"string")
   * @return bool $ok Booléen qui signale si l'ajout s'est bien passé
   */
  public function enregistrerOption($nomOption, $valOption, $typeOption='int', $prefix=null)
  {
    $prefix  = (is_null($prefix)) ? $this->prefix : $prefix;
    $requete = 'INSERT INTO '.$prefix.'options(nomOption, valOption, typeOption) VALUES(\''.$nomOption.'\', \''.$valOption.'\',\''.$typeOption.'\')';

    return $this->executer($requete);
  }

  /**
   * Méthode qui ajoute un tag en base dans la table "tag"
   *
   * @param string $nom Nom du tag à ajouter
   * @param int $idRoot ID de la catégorie de tags dans lequel le tag doit être ajouté
   * @return bool $ok Booléen qui signale si l'ajout s'est bien passé
   */
  public function enregistrerTag($nom, $idRoot)
  {
    $requete = 'INSERT INTO '.$this->prefix.'tag(nomTag, idRootTag) VALUES(\''.$nom.'\', '.(int)$idRoot.')';
    return $this->executer($requete);
  }
  
  /**
   * Méthode qui ajoute un utilisateur en base dans la table "utilisateur"
   *
   * @param string $login Login de l'utilisateur à ajouter
   * @param string $password Mot de passe de l'utilisateur à ajouter
   * @param string $prenom Prenom de l'utilisateur à ajouter
   * @param string $nom Nom de l'utilisateur à ajouter
   * @param bool $isAdmin Définit si l'utilisateur est admin ou non
   * @param bool $isUploader Définit si l'utilisateur peut ajouter des items
   * @param bool $isActif Définit si le compte est activé
   * @return bool $ok Booléen qui signale si l'ajout s'est bien passé
   */
  public function enregistrerUtilisateur($login, $password, $prenom, $nom, $mail, $isAdmin, $isUploader, $isActif, $prefix=null)
  {
    if(is_null($prefix))
      {
	$prefix = $CONF['sql_prefix'];
      }
    $id = $this->nextId('user');
    $requete = 'INSERT INTO '.$this->prefix.'utilisateur(idUtilisateur,loginUtilisateur, passwordUtilisateur, prenomUtilisateur, nomUtilisateur, mailUtilisateur, isAdmin, isUploader, isActif) '.
      'VALUES('.$id.',\''.$login.'\', \''.md5($password).'\', \''.$prenom.'\', \''.$nom.'\', \''.$mail.'\', '.(int)$isAdmin.', '.(int)$isUploader.', '.(int)$isActif.')';

    return $this->executer($requete);
  }
  
  /**
   * Méthode qui ajoute un item en base dans la table "item"
   *
   * @param string $nom Nom de l'item à ajouter
   * @param string $lien Lien de l'item à ajouter
   * @param string $icone Icone de l'item à ajouter
   * @param int $droits Droits sur l'item à ajouter
   * @param string $proprietaire Login du propriétaire de l'item à ajouter
   * @param int $type ID du type de l'item à ajouter
   * @param string $meta Metadonnées de l'item à ajouter
   * @param int $id Id passé en réference (idItem issu de l'INSERT)
   * @return bool $ok Booléen qui signale si l'ajout s'est bien passé
   */
  public function enregistrerItem($nom, $lien, $icone, $proprietaire, $type, $desc, $meta, &$id=0)
  {
    $id = $this->nextId();
    $requete = 'INSERT INTO '.$this->prefix.'item(idItem, nomItem, lienItem, iconeItem, dateAjoutItem, proprietaireItem, typeItem, metaItem, descItem) '.
      'VALUES('.$id.', \''.$nom.'\', \''.$lien.'\', \''.$icone.'\', SYSDATE(), \''.$proprietaire.'\', \''.$type.'\', \''.addslashes($meta).'\', \''.addslashes($desc).'\')';
    return $this->executer($requete);
  }

  /**
   * Methode qui associe un tag a un iten
   *
   * @param string $tag le tag
   * @param int $idItem l'id de l'item
   * @return boot $ok booleen qui signale si tout s'est bien passe
   */
  public function ajouterTagItem($tag, $idItem)
    {
      //--- il n'y a pas de contraintes réferencielle donc il faut vérifier que le tag existe avant de l'ajouter
      //--- si il n'existe pas alors le créer ou lancer une exception ?
      $this->enregistrerTag($tag,0);
      $requete = 'INSERT INTO '.$this->prefix.'tag_item(idItem, nomTag) VALUES('.(int)$idItem.',\''.$tag.'\')';
      return $this->executer($requete);
    }

  /* ------------------------------- */
  /* Méthodes de suppression en base */
  /* ------------------------------- */

  /**
   * Methode qui supprime l'association d'un tag a un iten
   *
   * @param string $tag le tag
   * @param int $idItem l'id de l'item
   * @return boot $ok booleen qui signale si tout s'est bien passe
   */
  public function supprimerTagItem($tag, $idItem)
    {
      $requete = 'DELETE FROM '.$this->prefix.'tag_item WHERE idItem='.(int)$idItem.' AND nomTag=\''.$tag.'\'';
      return $this->executer($requete);
    }


  /**
   * Méthode qui supprime un tag en base, dans les tables "tag" et "tag_item"
   *
   * @param string $nom Nom du tag à supprimer  
   * @return bool $ok Booléen qui signale si la suppression s'est bien passé
   */
  public function supprimerTag($nom)
  {
    $requete  = 'DELETE FROM '.$this->prefix.'tag WHERE nomTag = \''.$nom.'\'';
    $requete2 = 'DELETE FROM '.$this->prefix.'tag_item WHERE nomTag = \''.$nom.'\'';
    $result   =  $this->executer($requete);
    if($result)
      {
	return $this->executer($requete2);
      }

    return false;
  }

  /**
   * Méthode qui supprime un utilisateur en base
   *
   * @param string $login Login de l'utilisateur à supprimer  
   * @return bool $ok Booléen qui signale si la suppression s'est bien passé
   */
  public function supprimerUtilisateur($login)
  {
    // On donne ses items au premier admin créé
    $requete = '
      UPDATE '.$this->prefix.'item
      SET
      proprietaireItem = (SELECT loginUtilisateur FROM '.$this->prefix.'utilisateur WHERE isAdmin = 1 ORDER BY idUtilisateur ASC LIMIT 0,1)
      WHERE proprietaireItem = \''.$login.'\'';

    // On supprime l'utilisateur et ses droits
    $requete2 = 'DELETE FROM '.$this->prefix.'utilisateur WHERE loginUtilisateur = \''.$login.'\'';
    $requete3 = 'DELETE FROM '.$this->prefix.'droits WHERE login = \''.$login.'\'';

    return ($this->executer($requete2) && $this->executer($requete3) && $this->executer($requete));
  }
  
  /**
   * Méthode qui supprime un item en base, dans les tables "item" et "tag_item"
   *
   * @param int $id ID de l'item à supprimer
   * @return bool $ok Booléen qui signale si la suppression s'est bien passé
   */
  public function supprimerItem($id)
  {
    $requete  = 'DELETE FROM '.$this->prefix.'item WHERE idItem = '.(int)$id;
    $requete2 = 'DELETE FROM '.$this->prefix.'tag_item WHERE idItem = '.(int)$id;

    $result   =  $this->executer($requete);
    if($result)
      {
	return $this->executer($requete2);
      }

    return false;
  }
  
  /**
   * Méthode qui supprime les items d'un utilisateur en base
   *
   * @param string $login Login de l'utilisateur dont il faut supprimer les items
   * @return bool $ok Booléen qui signale si la suppression s'est bien passé
   */
  public function supprimerItemUtilisateur($login)
  {
    // Récupération des id à supprimer
    $requete1 = 'SELECT idItem FROM '.$this->prefix.'item WHERE proprietaireItem=\''.$login.'\'';
    $lesID = $this->doRequeteColonne($requete1);
    $lesID = implode('","', $lesID);

    // Suppression dans la table tag_item
    $requete2 = 'DELETE FROM '.$this->prefix.'tag_item WHERE idItem IN("'.$lesID.'")';

    // Suppression dans la table item
    $requete3 = 'DELETE FROM '.$this->prefix.'item WHERE idItem IN("'.$lesID.'")';

    $result   =  $this->executer($requete2);
    if($result)
      {
	return $this->executer($requete3);
      }

    return false;
  }

  /* -------------------------------- */
  /* Méthodes de modification en base */
  /* -------------------------------- */

  /**
   * Méthode qui modifie une option
   *
   * @param string $nomOption nom de l'option
   * @param string $valOption valeur de l'option
   * @return bool $ok Booléen qui signale si la modification s'est bien passé
   */
  public function modifierOption($nomOption, $valOption)
  {
    $requete = 'UPDATE '.$this->prefix.'options SET valOption=\''.$valOption.'\' WHERE nomOption=\''.$nomOption.'\'';

    return $this->executer($requete);
  }

  /**
   * Méthode qui renomme un tag en base dans les table "tag" et "tag_item"
   *
   * @param string $nom Nom du tag à modifier
   * @param string $nouveauNom Nouveau nom du tag à modifier
   * @return bool $ok Booléen qui signale si la modification s'est bien passé
   */
  public function renommerTag($nom, $nouveauNom)
  {
    $requete  = 'UPDATE '.$this->prefix.'tag SET nomTag=\''.$nouveauNom.'\' WHERE nomTag=\''.$nom.'\'';
    $requete2 = 'UPDATE '.$this->prefix.'tag_item SET nomTag=\''.$nouveauNom.'\' WHERE nomTag=\''.$nom.'\'';
    $result   =  $this->executer($requete);
    if($result)
      {
	return $this->executer($requete2);
      }

    return false;
  }

  /**
   * Méthode qui ajoute un Hit au tag
   *
   * @return bool $ok Booléen qui signale si tout s'est bien passé
   */
  public function ajouterHit($nom)
  {
    $requete  = 'SELECT hitTag FROM '.$this->prefix.'tag WHERE nomTag=\''.$nom.'\'';
    $result   = $this->doRequeteLigne($requete);
    $result2  = (int)$result['hitTag'];

    if(DB::isError($result)) return false;

    $result2++;
    $requete2 = 'UPDATE '.$this->prefix.'tag SET hitTag='.$result2.' WHERE nomTag=\''.$nom.'\'';

    return $this->executer($requete2);
  }
  
  /**
   * Méthode qui change un tag de categorie en base dans la table "tag"
   *
   * @param string $nom Nom du tag à modifier
   * @param int $idRoot ID de la catégorie de tags dans lequel le tag doit être
   * @return bool $ok Booléen qui signale si la modification s'est bien passé
   */
  public function changerRootTag($nom, $idRoot)
  {
    $requete = 'UPDATE '.$this->prefix.'tag SET idRootTag='.(int)$idRoot.' WHERE nomTag=\''.$nom.'\'';
    return $this->executer($requete);
  }

  /**
   * Méthode qui modifie un utilisateur en base dans la table "utilisateur"
   *
   * @param string $login Login de l'utilisateur à modifier
   * @param string $password Nouveau mot de passe de l'utilisateur
   * @param string $prenom Nouveau prenom de l'utilisateur
   * @param string $nom Nouveau nom de l'utilisateur
   * @param bool $isAdmin Définit si l'utilisateur est admin ou non
   * @param bool $isUploader Definit si l'utilisateur peut uploader ou non
   * @param bool $isActif Définit si le compte est actif
   * @return bool $ok Booléen qui signale si l'ajout s'est bien passé
   */
  public function majUtilisateur($id, $login, $password, $prenom, $nom, $mail, $isAdmin, $isUploader, $isActif)
  {
    if(is_null($password) 
       && is_null($prenom) 
       && is_null($nom) 
       && is_null($mail) 
       && is_null($isAdmin) 
       && is_null($isUploader)
       && is_null($isActif)) return false;

    if(!is_null($login))
      $set[] = 'loginUtilisateur=\''.$login.'\'';

    if(!is_null($password))
      $set[] = 'passwordUtilisateur=\''.md5($password).'\'';

    if(!is_null($prenom))
      $set[] = 'prenomUtilisateur=\''.$prenom.'\'';

    if(!is_null($nom))
      $set[] = 'nomUtilisateur=\''.$nom.'\'';

    if(!is_null($mail))
      $set[] = 'mailUtilisateur=\''.$mail.'\'';

    if(!is_null($isAdmin))
      $set[] = 'isAdmin=\''.(int)$isAdmin.'\'';

    if(!is_null($isUploader))
      $set[] = 'isUploader=\''.(int)$isUploader.'\'';

    if(!is_null($isActif))
      $set[] = 'isActif=\''.(int)$isActif.'\'';
	
    $requete = 'UPDATE '.$this->prefix.'utilisateur SET '.implode(', ', $set).
      ' WHERE idUtilisateur=\''.$id.'\'';

    return $this->executer($requete);
  }

  /**
   * Méthode qui modifie le nom d'un item en base dans la table "item"
   *
   * @param int $id ID de l'item à renommer
   * @param string $nouveauNom Nouveau nom de l'item
   * @return bool $ok Booléen qui signale si la modification s'est bien passé
   */
  public function renommerItem($id, $nouveauNom)
  {
    $requete = 'UPDATE '.$this->prefix.'item SET nomItem=\''.$nouveauNom.'\' WHERE idItem='.(int)$id;
    return $this->executer($requete);
  }
  
  /**
   * Méthode qui modifie la description d'un item en base dans la table "item"
   *
   * @param int $id ID de l'item à renommer
   * @param string $desc Nouvelle description de l'item
   * @return bool $ok Booléen qui signale si la modification s'est bien passé
   */
  public function changerDescItem($id, $desc)
  {
    $requete = 'UPDATE '.$this->prefix.'item SET descItem=\''.addslashes($desc).'\' WHERE idItem='.(int)$id;
    return $this->executer($requete);
  }

  /**
   * Methode qui met a jour le lien vers l'icone de l'item
   *
   * @param int $id id de l'item a metre a jour
   * @prama string $chemin chemin ou se trouve l'icone ou false si il y a eu une erreur
   * @return bool $ok booleen qui signale si tout s'est bien passe
   */
  public function iconeItem($id, $chemin)
  {
    if(false === $chemin)
      {
	$chemin = 'err';
      }

    $requete = 'UPDATE '.$this->prefix.'item SET iconeItem="'.$chemin.'" WHERE idItem='.(int)$id;
    return $this->executer($requete);
  }

  /**
   * Méthode qui change les droits d'un utilisateur par rapport a un item
   *
   * @param int $idItem id de l'item
   * @param string $login login de l'utilisateur
   * @param int $droits droits accordés (1= lecture, 2= tous les droits)
   * @return bool $ok vrai si tout s'est bien passé
   */
  public function changerDroitsItem($idItem, $login, $droits)
  {
    $requete = 'DELETE FROM '.$this->prefix.'droits WHERE idItem='.(int)$idItem.' AND login="'.$login.'"';
    $this->executer($requete);    

    $requete = 'INSERT INTO '.$this->prefix.'droits (idItem,login,droits)VALUES ('.(int)$idItem.', "'.$login.'", '.(int)$droits.');';
    return $this->executer($requete);
  }

  /**
   * Méthode qui rend l'item public ou privé selon $etat
   *
   * @param int $id id de l'item
   * @param bool $etat si vrai on veut du public si faux du privé
   * @return bool $ok vrai si tout s'est bien passé
   */
  public function changerPublicItem($id, $etat)
  {
    global $visiteur;
    if($etat) return $this->changerDroitsItem($id, $visiteur, 1);
    $requete = 'DELETE FROM '.$this->prefix.'droits WHERE idItem='.(int)$id.' AND login="'.$visiteur.'"';
    return $this->executer($requete);
  }

  /* --------------- */
  /* Autres méthodes */
  /* --------------- */

  /**
   * Méthode qui vérifie que le login et le password correspondent, et retourne ses infos si c'est le cas
   *
   * @param string $login Login de l'utilisateur
   * @param string $password Mot de passe de l'utilisateur
   * @return array Tableau contenant les infos de l'utilisateur
   */
  public function identification($login, $password)
  {
    $requete = 'SELECT * FROM '.$this->prefix.'utilisateur WHERE login=\''.$login.'\' AND password=\''.$password.'\'';
    $result = $this->doRequeteLigne($requete);

    return $result;
  }

  /**
   * Methode qui defini si le mode debug_sql doit etre active ou non
   *
   * @param bool $etat true = active, false = desactive
   */
  public function setDebug($etat = true)
  {
    $this->debug = $etat;
  }

  /**
   * Methode qui retourne le nombre d'administrateur
   *
   * @return int $nb Nombre d'administrateur
   */
  public function nombreAdmin()
  {
    $requete = 'SELECT loginUtilisateur FROM '.$this->prefix.'utilisateur WHERE isAdmin=1';
    $res = $this->sql->query($requete);

    return $res->numRows();
  }

  /* ---------------------------- */
  /* Méthode de création de table */
  /* ---------------------------- */

  /**
   * Méthode qui créer une nouvelle table
   *
   * @param string $requete requete de création de la table
   * @param string $drop requete de drop
   *
   * @return bool $ok vrai si tout s'est bien passé
   */
  public function createTable($requete, $drop=null)
  {
    $bool = true;
    if(!is_null($drop)) 
      {
	$bool = $this->executer($drop);
      }

    if($bool === false)
      {
	return false;
      }
    
    return $this->executer($requete);
  }

  /* --------------------------------- */
  /* Méthodes privées de la classe SQL */
  /* --------------------------------- */

  /**
   * Retourne la chaine SQL protege
   *
   * @param string $requete a proteger
   * @param bool $gpc indique si le string provient d'un GET, POST ou COOKIE
   * @return string $r requete protege
   */
  public function cleanSQL($requete, $gpc=false)
  {
    if(get_magic_quotes_gpc() && $gpc === true)
      {
	$requete = stripslashes($requete);
      }
    
    //--- pas sur de l'utilité
    $requete = cleanVar($requete);
    return $this->sql->escapeSimple($requete);
  }

  /**
   * Retourne le prochain Id de la séquence
   *
   * @param string $seq nom de la séquence
   * @return int $id id
   */
  public function nextId($seq=null)
  {
    if(is_null($seq))
      {
	$seq = 'item';
      }

    return $this->sql->nextId($this->prefix.$seq);
  }

  /**
   * Méthode qui exécute une requete qui retourne UNE seule ligne résultat
   *
   * @param string $requete Requête à exécuter  
   * @return array $t Tableau contenant le résultat de la requete
   */
  public function doRequeteLigne($requete)
  {
    $tdeb  = getMicroTime();
    $t     = $this->sql->getRow($requete);
    $temps = round(getMicroTime() - $tdeb, 4);

    if($this->debug === true) echo '<pre>"'.$requete.'" executé en '.$temps.' seconde(s)'.'</pre>';
    return $t;
  }
  
  /**
   * Méthode qui exécute une requete qui retourne PLUSIEURS lignes de résultats
   *
   * @param string $requete Requête à exécuter
   * @param int $f Début des enregistrements (LIMIT)
   * @param int $c Nombre d'enregistrement (LIMIT)
   * @return array $t Tableau contenant les lignes résultats de la requete
   */
  public function doRequeteLignes($requete, $f=null, $c=null)
  {
    $tdeb   = getMicroTime();
    if(is_null($f) || is_null($c))
      {
	$result = $this->sql->query($requete);
      }
    else
      {
	$result = $this->sql->limitQuery($requete, (int)$f, (int)$c);
      }
    
    if(DB::isError($result))
      {
	throw new ListerException($result->getMessage());
      }
    
    $var = array();
    
    while($ligne = $result->fetchRow())
      {
	$var[] = $ligne;
      }

    $temps = round(getMicroTime() - $tdeb, 4);

    if($this->debug === true) echo '<pre>"'.$requete.'" executé en '.$temps.' seconde(s)'.'</pre>';

    return $var;
  }
  
  /**
   * Méthode qui exécute une requete et retourne la colonne résultat demandée
   *
   * @param string $requete Requête à exécuter
   * @param int $numCol Numéro de la colonne à récupérer
   * @return array $t Tableau contenant les lignes résultats de la requete
   */
  public function doRequeteColonne($requete, $numCol=0)
  {
    $tdeb  = getMicroTime();
    $t     = $this->sql->getCol($requete, $numCol);
    $temps = round(getMicroTime() - $tdeb, 4);

    if($this->debug === true) echo '<pre>"'.$requete.'" executé en '.$temps.' seconde(s)'.'</pre>';
    return $t;
  }

  /**
   * Méthode qui execute une requete
   *
   * @param string $requete Requete a executer
   * @return bool $ok Retourne true si tout s'est bien passé
   */
  public function executer($requete)
  {
    $tdeb   = getMicroTime();
    $result = $this->sql->query($requete);
    $temps  = round(getMicroTime() - $tdeb, 4);

    if($this->debug === true) echo '<pre>"'.$requete.'" executé en '.$temps.' seconde(s)'.'</pre>';
    return (!DB::isError($result));
  }
  
  /**
   * Méthode qui retourne une chaine SQL WHERE avec les orthographe approchées du mot entré
   *
   * @param string $mot mot pour lequel on cherche l'orthographe
   * @param string $param nom du parametre SQL
   * @return string $requete chaine SQL pour clause WHERE
   */
   private function orthographeApproch($mot, $param)
    {
        $size = strlen($mot);
        $cpt  = 1;
        $tmp1=''; $tmp2='';
        $requete = " ".$param." LIKE ('%" . $mot . "') OR ";

        // Pour chaque lettre on la remplace par le joker sql % afin de faire un WHERE LIKE
        for (; $cpt < $size; $cpt++)
        {
            $tmp1 = substr($mot, 0, $cpt);
            $tmp2 = substr($mot, ($cpt + 1), ($size - $cpt - 1));
            $requete .= " ".$param." LIKE ('" . $tmp1 . '%' . $tmp2 . "') OR ";
        }

        $requete .= " ".$param." LIKE ('" . $mot . "%') ";

        return $requete;
    }
}

?>
